/*-----------------------------------------------------------------------------
	The contents of this file are subject to the Mozilla Public License
	Version 1.1 (the "License"); you may not use this file except in
	compliance with the License.You may obtain a copy of the License at
	http://www.mozilla.org/MPL/MPL-1.1.html
	
	Software distributed under the License is distributed on an "AS IS"
	basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
	License for the specific language governing rights and limitations
	under the License.
	
	The Original Code is Fever Framework code.
	
	The Initial Developer of the Original Code is Romain Ecarnot.
	Portions created by Initial Developer are Copyright (C) 2006
	the Initial Developer. All Rights Reserved.
	
	Contributor(s):
	
	Unless required by applicable law or agreed to in writing, software
	distributed under the License is distributed on an "AS IS" BASIS,
	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	See the License for the specific language governing permissions and
	limitations under the License.
-----------------------------------------------------------------------------*/

import com.bourre.commands.CommandManagerFPS;
import com.bourre.commands.Delegate;
import com.bourre.core.HashCodeFactory;
import com.bourre.data.collections.Map;
import com.bourre.events.EventBroadcaster;
import com.bourre.events.EventType;
import com.bourre.events.IEvent;
import com.bourre.structures.Rectangle;

import fever.core.CoreApplication;
import fever.core.FeverRoot;
import fever.display.background.Background;
import fever.display.background.SolidBackGround;
import fever.display.style.StageAlign;
import fever.display.style.StageScaleMode;
import fever.events.EventPriority;
import fever.events.StageEvent;
import fever.Fever;

/**
 * Core stage for UI creation.
 * 
 * <p>Use it to create UI component ( MovieClip or AsWing components for example )
 * 
 * <p>Support new player 9 feature 'Fullscreen mode'.
 * 
 * <p>{@link FeverStage} allow better levels managment defining pre-level like : 
 * <ul>
 *   <li>A level for bitmap loading ( hidden for user )</li>
 *   <li>A level for font loading ( hidden for user )</li>
 *   <li>An overlay level which put all created clip on the top</li>
 *   <li>A 'root' level for classic UI composition.</li>
 * <ul>
 * 
 * @author Romain Ecarnot
 */
class fever.display.FeverStage
{ 
	//-------------------------------------------------------------------------
	// Events definition
	//-------------------------------------------------------------------------

	/** Dispatched when {@code Stage.align} property change. */
	public static var onStageAlignChangeEVENT : EventType = StageEvent.onStageAlignChangeEVENT;
	
	/** Dispatched when {@code Stage.scaleMode} property change. */
	public static var onStageMenuChangeEVENT : EventType = StageEvent.onStageMenuChangeEVENT;
	
	/** Dispatched when {@code Stage.showMenu} property change. */
	public static var onStageScaleModeChangeEVENT : EventType = StageEvent.onStageScaleModeChangeEVENT;
	
	
	//-------------------------------------------------------------------------
	// Public Properties
	//-------------------------------------------------------------------------
	
	/** Hack to disallow Feverstage used for level creation. */
	public static var DISABLED_FEATURE : Boolean = false;
	
	/** Default background color value for stage object. */
	public static var DEFAULT_BACKGROUND_COLOR : Number;
	
	public static var FONT_LIB_LEVEL : Number = 2;	public static var DLL_LIB_LEVEL : Number = 3;
	public static var BITMAP_LIB_LEVEL : Number = 5;	public static var THEME_LIB_LEVEL : Number = 6;	public static var SOUND_LIB_LEVEL : Number = 7;	public static var BACKGROUND_LIB_LEVEL : Number = 10;	public static var ROOT_LIB_LEVEL : Number = 20;	public static var OVERLAY_LIB_LEVEL : Number = 10000;	public static var CURSOR_LIB_LEVEL : Number = 100001;	public static var LOGGER_LIB_LEVEL : Number = 1000000;
	
	
	//-------------------------------------------------------------------------
	// Private properties
	//-------------------------------------------------------------------------
	
	private static var _instance : FeverStage;
	
	private var _oEB : EventBroadcaster;
	private var _levelMap : Map;
	
	private var _align : String;
	private var _scaleMode : String;
	private var _showMenu : Boolean;	
	private var _backgroundStrategy : Background;
	
	
	//-------------------------------------------------------------------------
	// Public Properties
	//-------------------------------------------------------------------------
	
	/** Main MovieClip context for Fever application. */
	public static var context : MovieClip;
	
	/**	Returns {@code _level0} target. */
	public function get level0() : MovieClip { return _getMainLevel(); }
	
	/**	Returns application root target. */
	public function get root() : MovieClip { return _getLibLevel( ROOT_LIB_LEVEL ); }
	
	/**	Returns level dedicated to {@link fever.data.libs.BitmapLib} target. */
	public function get bitmapLevel() : MovieClip { return _getLibLevel( BITMAP_LIB_LEVEL ); }
	
	/**	Returns level dedicated to {@link fever.data.libs.FontLib} target. */
	public function get fontLevel() : MovieClip { return _getLibLevel( FONT_LIB_LEVEL ); }
	
	/**	Returns level dedicated to {@link fever.data.libs.ThemeLib} target. */
	public function get themeLevel() : MovieClip { return _getLibLevel( THEME_LIB_LEVEL); }
	
	/**	Returns level dedicated to {@link fever.data.libs.DLLLib} target. */
	public function get dllLevel() : MovieClip { return _getLibLevel( DLL_LIB_LEVEL); }
	
	/**	Returns level dedicated to {@link fever.display.background.Background} target. */
	public function get backgroundLevel() : MovieClip { return _getLibLevel( BACKGROUND_LIB_LEVEL ); }
	
	/**	Returns level dedicated to overlayed target. */
	public function get overlayLevel() : MovieClip { return _getLibLevel( OVERLAY_LIB_LEVEL ); }
	
	/**	Returns level dedicated to cursor target. */
	public function get cursorLevel() : MovieClip { return _getLibLevel( CURSOR_LIB_LEVEL ); }
	
	/**	Indicates if Flash menu is available. */
	public function get showMenu() : Boolean { return _showMenu; }
	public function set showMenu ( b : Boolean ) : Void
	{ 
		if( b != _showMenu )
		{
			_showMenu = b;
			Stage.showMenu = b;
			_fireEvent( StageEvent.onStageMenuChangeEVENT );
		}
	}
	
	/**	How the stage is scaled. */
	public function get scaleMode() : String { return _scaleMode; }
	public function set scaleMode ( p : String ) : Void
	{
		if( p != _scaleMode )
		{
			_scaleMode = p;
			Stage.scaleMode = p;
			
			_fireEvent( StageEvent.onStageScaleModeChangeEVENT );
		}
	}
	
	/**	How the stage is aligned. */
	public function get align() : String { return _align; }
	public function set align ( p : String ) : Void
	{ 
		if( p != _align )
		{
			_align = p;
			Stage.align = p;
			
			_fireEvent( StageEvent.onStageAlignChangeEVENT );
		}
	}
	
	
	//-------------------------------------------------------------------------
	// Public API
	//-------------------------------------------------------------------------
	
	/**
	 * Creates and returns {@link FeverStage} instance
	 * 
	 * <p>Always return the same instance ( Singleton desing ).
	 */
	public static function getInstance() : FeverStage
	{
		if( !_instance ) _instance = new FeverStage( );
		return _instance;	
	}
	
	/**
	 * Adds passed-in {@code listener} for receiving passed-in {@code type} event type.
	 * 
	 * @param type Name of the Event.
	 * @param listener Listener object.
	 */
	public function addEventListener( type : EventType, listener ) : Void
	{
		_oEB.addEventListener.apply( _oEB, arguments );	
	}
	
	/**
	 * Removes passed-in {@code listener} that subscribed to passed-in {@code type} event type.
	 * 
	 * @param type Name of the Event.
	 * @param listener Listener object.
	 */
	public function removeEventListener( type : EventType, listener ) : Void
	{
		_oEB.removeEventListener( type, listener );	
	}
	
	/**
	 * Broadcasts event to suscribed listeners.
	 * 
	 * @param event an <strong>IEvent</strong> instance
	 */
	public function broadcastEvent( event : IEvent ) : Void
	{
		_oEB.broadcastEvent( event );
	}
	
	/**
	 * Creates and returns a new empty MovieClip on {@code root} level.
	 * 
	 * <p>MovieClip depth is automatically calculated.
	 * 
	 * @param name ( optional ) MovieClip name
	 */
	public function createEmptyMovieClip( name : String ) : MovieClip
	{
		return _createLayer( _getLibLevel( ROOT_LIB_LEVEL ), name );
	}
	
	/**
	 * Creates and returns a new {@link fever.data.libs.FontLib} target.
	 * 
	 * @param name ( optional ) FontLib name
	 */ 
	public function createFontLibTarget( name : String ) : MovieClip
	{
		return _createLayer( _getLibLevel( FONT_LIB_LEVEL ), name );
	}
	
	/**
	 * Creates and returns a new {@link fever.data.libs.ThemeLib} target.
	 * 
	 * @param name ( optional ) ThemeLib name
	 */ 
	public function createThemeLibTarget( name : String ) : MovieClip
	{
		return _createLayer( _getLibLevel( THEME_LIB_LEVEL ), name );
	}
	
	/**
	 * Creates and returns a new {@link fever.data.libs.BitmapLib} target.
	 * 
	 * @param name ( optional ) BitmapLib name
	 */ 
	public function createBitmapLibTarget( name : String ) : MovieClip
	{
		return _createLayer( _getLibLevel( BITMAP_LIB_LEVEL ), name );
	}
	
	/**
	 * Creates and returns a new {@link fever.data.libs.SoundLib} target.
	 * 
	 * @param name ( optional ) SoundLib name
	 */ 
	public function createSoundLibTarget( name : String ) : MovieClip
	{
		return _createLayer( _getLibLevel( SOUND_LIB_LEVEL ), name );
	}
	
	/**
	 * Creates and returns a new {@link fever.data.libs.DLLLib} target.
	 * 
	 * @param name ( optional ) SoundLib name
	 */ 
	public function createDLLTarget( name : String ) : MovieClip
	{
		return _createLayer( _getLibLevel( DLL_LIB_LEVEL ), name );
	}
	
	/**
	 * Creates a new MovieClip target on overlay level.
	 * 
	 * <p>Means that MovieClip is at the top of rendering layer.
	 */
	public function createOverlayTarget() : MovieClip
	{
		return _createLayer( _getLibLevel( OVERLAY_LIB_LEVEL ) );
	}
	
	/**
	 * Creates cursor target in dedicated layer.
	 */
	public function createCursorTarget() : MovieClip
	{
		return _createLayer( _getLibLevel( CURSOR_LIB_LEVEL ) );	
	}
	
	/**
	 * Returns specific level to keep a possible logging view 
	 * on top of application.
	 */
	public function getLoggerTarget() : MovieClip
	{
		return _getLibLevel( LOGGER_LIB_LEVEL );
	}
	
	/**
	 * Sets a new {@link fever.display.background.Background} for 
	 * application.
	 */
	public function setBackground( b : Background ) : Void
	{
		if( b != _backgroundStrategy )
		{
			_backgroundStrategy.clear( _getLibLevel( BACKGROUND_LIB_LEVEL ) );
			_backgroundStrategy = b;
			_repaint();	
		}
	}
	
	/**
	 * Returns current {@link fever.display.background.Background}
	 */
	public function getBackground() : Background
	{
		return _backgroundStrategy;
	}
	
	/**
	 * Don't use this method ! <br />
	 * Fever core class used it for correct stage initialisation.
	 */
	public function init() : Void
	{
		if( !DISABLED_FEATURE ) 
			Fever.application.addEventListener( CoreApplication.onResizeEVENT, this, _repaint, EventPriority.HIGHER );
			
		_repaint();	
	}
	
	/**
	 * 
	 */
	public function _getMainLevel( ) : MovieClip
	{
		return ( !context ) ? ( !FeverRoot.LEVEL ? _root : FeverRoot.LEVEL )  : context;
	}
	
	
	//-------------------------------------------------------------------------
	// Private implementation
	//-------------------------------------------------------------------------
	
	/**
	 * Constructor.
	 */
	private function FeverStage( )
	{
		_oEB = new EventBroadcaster( this );
		
		_levelMap = new Map();
		_levelMap.put( FONT_LIB_LEVEL, '__fontLibLevel__' );		_levelMap.put( DLL_LIB_LEVEL, '__dllLevel__' );		_levelMap.put( BITMAP_LIB_LEVEL, '__bitmapLibLevel__' );		_levelMap.put( THEME_LIB_LEVEL, '__themeLibLevel__' );		_levelMap.put( SOUND_LIB_LEVEL, '__soundLibLevel__' );		_levelMap.put( BACKGROUND_LIB_LEVEL, '__backgroundLevel__' );		_levelMap.put( ROOT_LIB_LEVEL, '__root__' );		_levelMap.put( OVERLAY_LIB_LEVEL, '__overlay__' );		_levelMap.put( CURSOR_LIB_LEVEL, '__cursor__' );		_levelMap.put( LOGGER_LIB_LEVEL, '__logger__' );
		
		if( DISABLED_FEATURE ) return;
		
		Stage.scaleMode = StageScaleMode.NO_SCALE;
		Stage.align = StageAlign.TOP_LEFT;
		
		_backgroundStrategy = new SolidBackGround( DEFAULT_BACKGROUND_COLOR );
	}
	
	/**
	 * Returns MovieClip target registred with passed-in {@code levelID} 
	 * identifier.
	 * 
	 * <p>If not exist, creates target.
	 */
	private function _getLibLevel( levelID : Number ) : MovieClip 
	{
		var mc : MovieClip;
		var mainLevel : MovieClip = _getMainLevel( );
		
		if( mainLevel.getInstanceAtDepth( levelID ).getDepth() == undefined )
		{
			mc = mainLevel.createEmptyMovieClip( _levelMap.get( levelID ), levelID );
		}
		else mc =  mainLevel.getInstanceAtDepth( levelID );
		
		return mc;
	}
	
	private function _fireEvent( type : EventType ) : Void
	{
		broadcastEvent( new StageEvent( type, this ) );
	}
	
	private function _createLayer( target : MovieClip, name : String ) : MovieClip
	{
		var depth : Number = target.getNextHighestDepth();
		if( !name ) name = _getName( depth );
		
		var mc : MovieClip = target.createEmptyMovieClip( name, depth );
		return mc;
	}
	
	private function _getName( depth : Number ) : String
	{
		return HashCodeFactory.getNextName() + depth;
	}
	
	private function _repaint() : Void
	{
		var size : Rectangle = Fever.application.getSize();
		
		if( size.width && size.height )
		{
			_backgroundStrategy.paintBackground( _getLibLevel( BACKGROUND_LIB_LEVEL ), size.width, size.height );
		}
		else CommandManagerFPS.getInstance().delay( new Delegate( this, _repaint ) );
		
	}
}